#include <iostream>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <cstring>
#include <cstdio>
#include <memory>
#include "PThread.hpp"
using namespace std;
// //int g_val = 100; //全局变量是所有线程都能看见的，就算修改了也都能看见
// __thread int g_val=100;   //加上__thread可以将内置类型设置为线性局部存储
// //分离线程：让父线程不在等待子线程执行完，就可以回收资源
// //把pthread_seif()的线程ID改成16进制的
// string changeId(const pthread_t &thread_id)
// {
//     char name[128];
//     snprintf(name,sizeof name,"0x%x",thread_id);  //
//     return name;
// }
// void* start_routine(void* args)
// {
//     string thread_name = static_cast<const char*>(args);  //安全的强制类型转化
//     //(pthread_self()); //线程分离，线程分离之后就可以不用join阻塞等待了
//     int n=5;
//     while(n--)
//     {
//         cout<<"son_pthread_ID="<<changeId(pthread_self())<<" g_val = "<<(int)g_val<<" &g_val = "<<&g_val<<endl;
//         sleep(1);
//         g_val++;
//     }
//     return nullptr;
// }

// int main()
// {
//     pthread_t pit;
//     int n =  pthread_create(&pit,nullptr,start_routine,(void*)"thread_one");
//     // pthread_detach(pit);
//     int t=6;
//     while(t--)
//     {
//         cout<<"son thread_ID="<<changeId(pit)<<" main thread_id = "<<changeId(pthread_self())<<" g_val = "<<(int)g_val<<" &g_val = "<<&g_val<<endl;
//         sleep(1);
//     }

//     // //一个线程默认是jionable的，如果设置了分离状态，不能够进行等待了
//     int flag = pthread_join(pit,nullptr);
//     cout<<"result: "<<flag<<" : "<<strerror(flag)<<endl;
//     return 0;
// }

int tickets=1000;   //共享资源火车票
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;   //该锁如果是局部的，或者静态的必须使用init进行初始化
void* getTick(void* args)
{
    //如何看待锁
        //a、锁，本身就是共享资源！全局的变量是需要被保护的，锁是用来保护全局的资源的，锁本身也是全局资源，锁的安全谁来保护呢
        //b、pthread_mutex_lock、pthread_mutex_unlock:加锁的过程必须是安全的！加锁的过程其实是原子的！
        //c、如果申请成功，就会继续向后执行，如果申请暂时没有成果，执行流会阻塞
        //d、谁持有锁，谁进入临界区
    //2、如何理解加锁和解锁的本质，-----加锁的过程是原子的！
    //3. 如果我们想简单的使用，该如何进行封装设计 --- 做一个设计


// 1. 多个执行流进行安全访问的共享资源 - 临界资源
// 2. 我们把多个执行流中，访问临界资源的代码 -- 临界区 -- 往往是线程代码的很小的一部分
// 3. 想让多个线程串行访问共享资源 -- 互斥
// 4. 对一个资源进行访问的时候，要么不做，要么做完 -- 原子性 ， 不是原子性的情况 -- 一个对资源进行的操作，如果只用一条汇编就能完成 -- 原子性
// 反之：不是原子的 -- 当前理解，方便表述

// 提出解决方案：加锁！

// 就需要尽可能的让多个线程交叉执行
// 多个线程交叉执行本质：就是让调度器尽可能的频繁发生线程调度与切换
// 线程一般在什么时候发生切换呢？时间片到了，来了更高优先级的线程，线程等待的时候。
// 线程是在什么时候检测上面的问题呢？从内核态返回用户态的时候，线程要对调度状态进行检测，如果可以，就直接发生线程切换

    std::string username = static_cast<const char *>(args);  
    while (true)
    {
        // 加锁和解锁的过程多个线程串行执行的，程序变慢了！
        // 锁只规定互斥访问，没有规定必须让谁优先执行
        // 锁就是真是的让多个执行流进行竞争的结果
        pthread_mutex_lock(&lock);   //加锁
        if (tickets > 0)
         {
            usleep(1254); // 1秒 = 1000毫秒 = 1000 000 微妙 = 10^9纳秒  
            //调用usleep的时候，会从用户态转向内核态
            std::cout << username << " 正在进行抢票: " << tickets << std::endl;
            tickets--;
            pthread_mutex_unlock(&lock);    //加锁和解锁的过程只针对于对临界资源的访问，也就是临界取的代码
        }
        else
        {
            pthread_mutex_unlock(&lock);
            break;
        }
    }
    return nullptr;

}

int main()
{
    unique_ptr<Thread> thread1(new Thread(getTick,(void*)"usr1",1));
    unique_ptr<Thread> thread2(new Thread(getTick,(void*)"usr2",2));
    unique_ptr<Thread> thread3(new Thread(getTick,(void*)"usr3",3));
    unique_ptr<Thread> thread4(new Thread(getTick,(void*)"usr4",4));

    thread1->join();
    thread2->join();
    thread3->join();
    thread4->join();

    return 0;


}